#include "StdAfx.h"
#include "ServerReadStrategy.h"
#include "RdcTransport.h"
#include "ServerChannelCore.h"

rdc_transport::ServerReadWithProtocol::ServerReadWithProtocol(IReader* internalRead)
: internalRead_(internalRead)
{
}

void rdc_transport::ServerReadWithProtocol::Read(Buffer* buffer)
{
    bool bReadNext = true;
    while (bReadNext)
    {
        char tempBuffer[CHANNEL_PDU_LENGTH];
        DWORD dwBytesRead = 0;

        internalRead_->ReadFile(tempBuffer, CHANNEL_PDU_LENGTH, &dwBytesRead);

        CHANNEL_PDU_HEADER header;
        ::memcpy(&header, tempBuffer, sizeof(CHANNEL_PDU_HEADER));
        bReadNext = !(header.flags & CHANNEL_FLAG_LAST);

        if (header.flags & CHANNEL_FLAG_FIRST)
        {
            buffer->resize(0);
            buffer->reserve(header.length);
        }

        buffer->insert(
            buffer->end(),
            tempBuffer + sizeof(CHANNEL_PDU_HEADER),
            tempBuffer + dwBytesRead);
    }
}

rdc_transport::ServerReadNoProtocol::ServerReadNoProtocol(IReader* internalRead)
: internalRead_(internalRead)
, m_dwReadBufferRemainder(0)
{
}

void rdc_transport::ServerReadNoProtocol::Read(Buffer* buffer)
{
    DWORD dwSize = 0;
    if (sizeof(DWORD) > m_dwReadBufferRemainder) //if we read less than "size" bytes on the previous time
    {
        for (DWORD i = 0; i < m_dwReadBufferRemainder; ++i)
        {
            ((PCHAR)&dwSize)[i] = m_pReadBuffer[i]; //fill dwSize with the previous incomplete size field
        }

        for (DWORD dwLeft = sizeof(DWORD) - m_dwReadBufferRemainder; dwLeft; )
        {
            internalRead_->ReadFile(m_pReadBuffer, CHANNEL_CHUNK_LENGTH, &m_dwReadBufferRemainder);

            if (m_dwReadBufferRemainder >= dwLeft)
            {
                for (DWORD i = 0; i < dwLeft; ++i) //fill dwSize with the last part of size field
                {
                    ((PCHAR)&dwSize)[sizeof(DWORD) - dwLeft + i] = m_pReadBuffer[i];
                }

                m_dwReadBufferRemainder -= dwLeft;
                ::memmove(m_pReadBuffer, m_pReadBuffer + dwLeft, m_dwReadBufferRemainder);
                dwLeft = 0;
            }
            else
            {
                for (DWORD i = 0; i < m_dwReadBufferRemainder; ++i) //fill dwSize with the next part of size field
                {
                    ((PCHAR)&dwSize)[sizeof(DWORD) - dwLeft + i] = m_pReadBuffer[i];
                }

                dwLeft -= m_dwReadBufferRemainder;
            }
        }
    }
    else
    {
        dwSize = *reinterpret_cast<DWORD*>(m_pReadBuffer);
        m_dwReadBufferRemainder -= sizeof(DWORD);
        ::memmove(m_pReadBuffer, m_pReadBuffer + sizeof(DWORD), m_dwReadBufferRemainder);
    }

    ATLASSERT(dwSize);
    buffer->reserve(dwSize);

    if (m_dwReadBufferRemainder >= dwSize)
    {
        buffer->insert(
            buffer->end(),
            m_pReadBuffer,
            m_pReadBuffer + dwSize);

        m_dwReadBufferRemainder -= dwSize;

        ::memmove(
            m_pReadBuffer,
            m_pReadBuffer + dwSize,
            m_dwReadBufferRemainder);
    }
    else
    {
        buffer->insert(
            buffer->end(),
            m_pReadBuffer,
            m_pReadBuffer + m_dwReadBufferRemainder);

        for (DWORD dwLeft = dwSize - m_dwReadBufferRemainder; dwLeft; )
        {
            internalRead_->ReadFile(m_pReadBuffer, CHANNEL_CHUNK_LENGTH, &m_dwReadBufferRemainder);

            if (m_dwReadBufferRemainder >= dwLeft)
            {
                buffer->insert(
                    buffer->end(),
                    m_pReadBuffer,
                    m_pReadBuffer + dwLeft);

                m_dwReadBufferRemainder -= dwLeft;
                ::memmove(m_pReadBuffer, m_pReadBuffer + dwLeft, m_dwReadBufferRemainder);
                dwLeft = 0;
            }
            else
            {
                buffer->insert(
                    buffer->end(),
                    m_pReadBuffer,
                    m_pReadBuffer + m_dwReadBufferRemainder);

                dwLeft -= m_dwReadBufferRemainder;
            }
        }
    }
}